#pragma once

#include<iostream>
#include<vector>
#include"Thread.hpp"
#include<queue>
#include<pthread.h>

using namespace ThreadModule;

const static int gdefaultthreadnum=3;

template<typename T>
class ThreadPool
{

private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void ThreasSleep()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    void ThreadWakeUp()
    {
        pthread_cond_signal(&_cond);
    }
public:
    ThreadPool(int threadnum=gdefaultthreadnum)
    :_threadnum(threadnum),_waitnum(0),_isrunning(false)
    
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }
    void HandlerTask(std::string name)
    {
        while(true)
        {
            LockQueue();
            while(_task_queue.empty() && _isrunning)
            {
                _waitnum++;
                ThreasSleep();
                _waitnum--;
            }
            sleep(1);
            if(!_task_queue.empty()&& _isrunning)
            {
                T t=_task_queue.front();
                _task_queue.pop();
            }
            unLockQueue();
            t(); 
        }
    }
    void InitThreadPool()
    {
        //只构建，不启动
        for(int num=0;num<_threadnum;num++)
        {
            std::string name="thread-"+std::to_string(num);
            _threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::1),name);
        }
    }

    void Enqueue(const T &t)
    {
        bool ret=false;
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(t);
            if(_waitnum>0)
            {
                ThreadWakeUp();
            }
            ret=true;
        }
        UnLockQueue();
        return ret;
    }
    
    void stop()
    {
        _isrunning=false;
    }
    void Start()
    {
        for(auto & thread : _threads)
        {
            thread.Start();
        }
        _isrunning=true;
    }
    void Wait()
    {
        for(auto & thread : _threads)
        {
            thread.Join();
        }
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _threadnum;
    std::vector<Thread> _threads;
    std:: queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    bool _isrunning;
    int _waitnum;
};

